/**
 * 
 */
package info.sswap.ontologies.modularity.owlapi;

import info.sswap.ontologies.modularity.Module;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.io.RDFXMLOntologyFormat;
import org.semanticweb.owlapi.io.StreamDocumentTarget;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAnnotationAssertionAxiom;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyChange;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.OWLOntologyStorageException;

/**
 * @author Pavel Klinov
 *
 */
public class OWLAPIModule implements Module {

	private static final IRI RDFS_IS_DEFINED_BY = IRI.create("http://www.w3.org/2000/01/rdf-schema#isDefinedBy");
	
	private OWLOntology mOntology = null;
	private Set<URI> mSignature = null;
	
	public OWLAPIModule() {
		try {
			mOntology = OWLManager.createOWLOntologyManager().createOntology();
		} catch (OWLOntologyCreationException e) {
			// this is lame
			throw new RuntimeException("Some is wrong with the OWL API if we can't create an ampty ontology");
		}
	}
	
	public OWLAPIModule(OWLOntology module) {
		mOntology = module;
	}
	
	@Override
	public Set<URI> getSignature() {
		
		if (mSignature == null) {
			mSignature = new HashSet<URI>();
			
			for (OWLEntity entity : mOntology.getSignature()) {
				if (entity.isOWLClass() || entity.isOWLObjectProperty() || entity.isOWLDataProperty()) {
					mSignature.add(entity.getIRI().toURI());
				}
			}
		}
		
		return mSignature;
	}

	@Override
	public String getModelAPI() {
		return "OWL API";
	}
	
	public OWLOntology getOWLAPIModel() {
		return mOntology;
	}

	@Override
	public URI getDefiningOntologyURI(URI term) {
		
		for (OWLAnnotationAssertionAxiom annotation : mOntology.getAnnotationAssertionAxioms(IRI.create(term))) {
			if (RDFS_IS_DEFINED_BY.equals(annotation.getAnnotation().getProperty().getIRI())) {
				String value = annotation.getAnnotation().getValue().toString();
				
				if (value.startsWith("\"") && value.endsWith("\"")) {
					value = value.substring(1, value.length() - 1);
				}
				
				return URI.create(value);
			}
		}
		
		return null;
	}

	@Override
	public Module union(Module module) {
		if (module.getModelAPI().equals(getModelAPI())) {
			//union two OWL API ontologies
			OWLOntologyManager mgr = mOntology.getOWLOntologyManager();
			List<OWLOntologyChange> changes = mgr.addAxioms(mOntology, ((OWLAPIModule)module).getOWLAPIModel().getAxioms());
			
			mgr.applyChanges(changes);
			
			return this;
		}
		else {
			// TODO Auto-generated method stub
			throw new UnsupportedOperationException("Not yet implemented");
		}
	}

	@Override
	public void write(OutputStream stream) throws IOException {
		try {
			mOntology.getOWLOntologyManager().saveOntology(mOntology, new RDFXMLOntologyFormat(), new StreamDocumentTarget(stream));
		} catch (OWLOntologyStorageException e) {
			throw new IOException(e);
		}
	}

	@Override
	public boolean isEmpty() {
		return mOntology.getAxioms().isEmpty();
	}
}